home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / pop2serv.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  21KB  |  974 lines

  1. /* POP2 Server state machine - see RFC 937
  2.  *
  3.  *  also see other credits in popcli.c
  4.  *  10/89 Mike Stockett wa7dyx
  5.  *  Modified 5/27/90 by Allen Gwinn, N5CKP, for later NOS releases.
  6.  *  Added to NOS by PA0GRI 2/6/90 (and linted into "standard" C)
  7.  *
  8.  *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
  9.  *              Extensive bug fixes, changed uses of Borland stat()
  10.  *              to fsize() in order to fix intermittent crashes
  11.  *
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #include <time.h>
  17.  
  18. #include <sys/stat.h>
  19. #ifdef UNIX
  20. #include <sys/types.h>
  21. #endif
  22. #if     defined(__STDC__) || defined(__TURBOC__)
  23. #include <stdarg.h>
  24. #endif
  25. #include <ctype.h>
  26. #include <setjmp.h>
  27. #include "global.h"
  28. #include "mbuf.h"
  29. #include "cmdparse.h"
  30. #include "socket.h"
  31. #include "proc.h"
  32. #include "files.h"
  33. #include "smtp.h"
  34. #include "mailcli.h"                    /* N1BEE */
  35. #include "dirutil.h"
  36.  
  37. #ifdef linux
  38. extern int unlink __ARGS((char *));
  39. #endif
  40.  
  41. #ifdef POP2SERVER
  42.  
  43. #undef DEBUG                            /* N1BEE */
  44.  
  45.  
  46. /* ---------------- common server data structures ---------------- */
  47.  
  48. /* POP server control block */
  49.  
  50. struct pop_scb {
  51.     int     socket;         /* socket number for this connection */
  52.     char    state;          /* server state */
  53. #define         LSTN    0
  54. #define         AUTH    1
  55. #define         MBOX    2
  56. #define         ITEM    3
  57. #define         NEXT    4
  58. #define         DONE    5
  59.     char    buf[TLINELEN+1];        /* input line buffer */
  60.     char    count;          /* line buffer length */
  61.     char    username[32];   /* user/folder name */
  62.     FILE    *wf;            /* work folder file pointer */
  63.     int     folder_len;     /* number of msgs in current folder */
  64.     int     msg_num;        /* current msg number */
  65.     long    msg_len;        /* length of current msg */
  66.     int     msg_status_size; /* size of the message status array */
  67.     long    curpos;         /* current msg's position in file */
  68.     long    folder_file_size; /* length of the current folder file, in bytes */
  69.     long    nextpos;        /* next msg's position in file */
  70.     char    folder_modified; /* mail folder contents modified flag */
  71.     int16   *msg_status;    /* message status array pointer */
  72. };
  73.  
  74. #define NULLSCB         (struct pop_scb *)0
  75.  
  76. /* Response messages */
  77.  
  78. static char     count_rsp[]    = "#%d messages in this folder\n",
  79.         error_rsp[]    = "- ERROR: %s\n",
  80.         greeting_msg[] = "+ POP2 %s\n",
  81. /*              length_rsp[]   = "=%ld bytes in this message\n", */
  82.         length_rsp[]   = "=%ld characters in Message #%d\n",
  83.         msg_line[]     = "%s\n",
  84.         no_mail_rsp[]  = "+ No mail, sorry\n",
  85.         no_more_rsp[]  = "=%d No more messages in this folder\n",
  86.         signoff_msg[]  = "+ Bye, thanks for calling\n";
  87.  
  88. static void rrip __ARGS((char *s));
  89. static struct pop_scb *create_scb __ARGS((void));
  90. static void delete_scb __ARGS((struct pop_scb *scb));
  91. static void popserv __ARGS((int s,void *unused,void *p));
  92. static int poplogin __ARGS((char *pass,char *username));
  93.  
  94. static void pop_sm __ARGS((struct pop_scb *scb));
  95.  
  96. static int Spop = -1; /* prototype socket for service */
  97.  
  98.  
  99. /* Start up POP receiver service */
  100. int
  101. #ifdef PROTOTYPES
  102. pop2start(int argc,char **argv,void *p)
  103. #else
  104. pop2start(argc,argv,p)
  105.  
  106. int argc;
  107. char *argv[];
  108. void *p;
  109. #endif
  110.  
  111. {
  112.     struct sockaddr_in lsocket;
  113.     int s;
  114.  
  115.     if (Spop != -1) {
  116.         return 0;
  117.     }
  118.  
  119.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  120.     chname(Curproc,"POP2 listener");
  121.  
  122.     lsocket.sin_family = AF_INET;
  123.     lsocket.sin_addr.s_addr = INADDR_ANY;
  124.     if(argc < 2)
  125.         lsocket.sin_port = IPPORT_POP2;
  126.     else
  127.         lsocket.sin_port = atoi(argv[1]);
  128.  
  129.     Spop = socket(AF_INET,SOCK_STREAM,0);
  130.  
  131.     bind(Spop,(char *)&lsocket,sizeof(lsocket));
  132.  
  133.     listen(Spop,1);
  134.  
  135.     for (;;) {
  136.         if((s = accept(Spop,NULLCHAR,(int *)NULL)) == -1)
  137.             break;  /* Service is shutting down */
  138.  
  139.         /* Spawn a server */
  140.  
  141.         newproc("POP2 server",4096,popserv,s,NULL,NULL,0);
  142.     }
  143.     return 0;
  144. }
  145.  
  146. /* Shutdown POP2 service (existing connections are allowed to finish) */
  147.  
  148. int
  149. #ifdef PROTOTYPES
  150. pop2stop(int argc,char **argv,void *p)
  151. #else
  152. pop2stop(argc,argv,p)
  153. int argc;
  154. char *argv[];
  155. void *p;
  156. #endif
  157.  
  158. {
  159.     if(Spop != -1) {
  160.         close_s(Spop);
  161.         Spop = -1;
  162.     } else
  163.         tprintf("No POP2 listener to stop\n");
  164.     return 0;
  165. }
  166.  
  167. static void
  168. popserv(s,unused,p)
  169. int s;
  170. void *unused;
  171. void *p;
  172. {
  173.     struct pop_scb *scb;
  174.     char *cp;
  175.  
  176.     sockowner(s,Curproc);           /* We own it now */
  177.     log(s,"open POP2");
  178.  
  179.     if((scb = create_scb()) == NULLSCB) {
  180.         tprintf(Nospace);
  181.         log(s,"close POP2 - no space");
  182.         close_s(s);
  183.         return;
  184.     }
  185.  
  186.     scb->socket = s;
  187.     scb->state  = AUTH;
  188.  
  189.     (void) usprintf(s,greeting_msg,Hostname);
  190.  
  191. loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  192.         /* He closed on us */
  193.  
  194.         goto quit;
  195.     }
  196.  
  197.     rrip(scb->buf);         /* Was "rip()" not "rrip()" -- N1BEE */
  198.     if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  199.         goto loop;
  200.  
  201. #ifdef DEBUG
  202.     if(Mailtrace >= 3) {
  203.         tprintf("POP2SERV(popserv): Processing line <%s>\n",scb->buf);
  204.         /* getch(); */
  205.     }
  206. #endif /* DEBUG */
  207.  
  208.     /* Convert lower, and mixed case commands to UPPER case - Ashok */
  209.     for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
  210.         *cp = toupper(*cp);
  211.  
  212.     pop_sm(scb);
  213.     if (scb->state == DONE)
  214.         goto quit;
  215.  
  216.     goto loop;
  217.  
  218. quit:
  219.     log(scb->socket,"close POP2");
  220.     close_s(scb->socket);
  221.     delete_scb(scb);
  222. }
  223.  
  224.  
  225. /* Create control block, initialize */
  226.  
  227. static struct
  228. pop_scb *create_scb()
  229. {
  230.     register struct pop_scb *scb;
  231.  
  232.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  233.         return NULLSCB;
  234.  
  235.     scb->username[0] = '\0';
  236.     scb->msg_status = NULL;
  237.     scb->wf = NULL;
  238.  
  239.     scb->count = scb->folder_file_size = scb->msg_num = 0;
  240.  
  241.     scb->folder_modified = FALSE;
  242.     return scb;
  243. }
  244.  
  245.  
  246. /* Free resources, delete control block */
  247.  
  248. static void
  249. delete_scb(scb)
  250. register struct pop_scb *scb;
  251. {
  252.  
  253.     if (scb == NULLSCB)
  254.         return;
  255.     if (scb->wf != NULL)
  256.         fclose(scb->wf);
  257.     if (scb->msg_status  != NULL)
  258.         free((char *)scb->msg_status);
  259.  
  260.     free((char *)scb);
  261. }
  262.  
  263. /* replace terminating end of line marker(s) (\r and \n) with null */
  264. static void
  265. rrip(s)
  266. register char *s;
  267. {
  268.     register char *cp;
  269.  
  270.     if((cp = strchr(s,'\r')) != NULLCHAR)
  271.         *cp = '\0';
  272.     if((cp = strchr(s,'\n')) != NULLCHAR)
  273.         *cp = '\0';
  274. }
  275.  
  276. /* --------------------- start of POP server code ------------------------ */
  277.  
  278. #define BITS_PER_WORD   16
  279.  
  280. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))   /* Start Of Message */
  281.  
  282. /* Command string specifications */
  283.  
  284. static char     ackd_cmd[] = "ACKD",
  285.         acks_cmd[] = "ACKS",
  286. #ifdef POP_FOLDERS
  287.         fold_cmd[] = "FOLD ",
  288. #endif
  289.         login_cmd[] = "HELO ",
  290.         nack_cmd[] = "NACK",
  291.         quit_cmd[] = "QUIT",
  292.         read_cmd[] = "READ",
  293.         retr_cmd[] = "RETR";
  294.  
  295. static void
  296. pop_sm(scb)
  297. struct pop_scb *scb;
  298. {
  299.     char password[30];
  300. #ifndef __TURBOC__
  301.     static
  302. #endif
  303.     void state_error(struct pop_scb *,char *);
  304. #ifndef __TURBOC__
  305.     static
  306. #endif
  307.     void open_folder(struct pop_scb *);
  308. #ifndef __TURBOC__
  309.     static
  310. #endif
  311.     void do_cleanup(struct pop_scb *);
  312. #ifndef __TURBOC__
  313.     static
  314. #endif
  315.     void read_message(struct pop_scb *);
  316. #ifndef __TURBOC__
  317.     static
  318. #endif
  319.     void retrieve_message(struct pop_scb *);
  320. #ifndef __TURBOC__
  321.     static
  322. #endif
  323.     void deletemsg(struct pop_scb *,int);
  324. #ifndef __TURBOC__
  325.     static
  326. #endif
  327.     void get_message(struct pop_scb *,int);
  328. #ifndef __TURBOC__
  329.     static
  330. #endif
  331.     void print_message_length(struct pop_scb *);
  332. #ifndef __TURBOC__
  333.     static
  334. #endif
  335.     void close_folder(struct pop_scb *);
  336. #ifdef POP_FOLDERS
  337. #ifndef __TURBOC__
  338.     static
  339. #endif
  340.     void select_folder(struct pop_scb *);
  341. #endif
  342.  
  343.     if (scb == NULLSCB)     /* be certain it is good -- wa6smn */
  344.         return;
  345.  
  346.     switch(scb->state) {
  347.     case AUTH:
  348. #ifdef DEBUG
  349.         if(Mailtrace >= 3)
  350.             tprintf("POP2SERV(pop_sm): Entering case AUTH\n");
  351. #endif /* DEBUG */
  352.         if (strncmp(scb->buf,login_cmd,strlen(login_cmd)) == 0){
  353.             sscanf(scb->buf,"HELO %31s %29s",scb->username,password);
  354. #ifdef DEBUG
  355.             if(Mailtrace >= 3) {
  356.                 tprintf("POP2SERV(pop_sm): Processing USER %s PASS %s\n",scb->username,password);
  357.                 tprintf("POP2SERV(pop_sm): Calling poplogin() for %s:%s:\n",scb->username,password);
  358.             }
  359. #endif /* DEBUG */
  360.  
  361.             if (!poplogin(scb->username,password)) {
  362.                 log(scb->socket,"POP2 access DENIED to %s",
  363.                         scb->username);
  364.                 state_error(scb,"Access DENIED!!");
  365.                 return;
  366.             }
  367.  
  368.             log(scb->socket,"POP2 access granted to %s",
  369.                     scb->username);
  370.             open_folder(scb);
  371.         } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  372.             do_cleanup(scb);
  373.         } else
  374.             state_error(scb,"(AUTH) Expected HELO or QUIT command");
  375. #ifdef DEBUG
  376.         if(Mailtrace >= 3)
  377.             tprintf("POP2SERV(pop_sm): Leaving case AUTH\n");
  378. #endif /* DEBUG */
  379.         break;
  380.  
  381.     case MBOX:
  382.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  383.             read_message(scb);
  384.  
  385. #ifdef POP_FOLDERS
  386.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  387.             select_folder(scb);
  388.  
  389. #endif
  390.  
  391.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0) {
  392.             do_cleanup(scb);
  393.         } else
  394.             state_error(scb,
  395. #ifdef POP_FOLDERS
  396.                     "(MBOX) Expected FOLD, READ, or QUIT command");
  397. #else
  398.                     "(MBOX) Expected READ or QUIT command");
  399. #endif
  400.         break;
  401.  
  402.     case ITEM:
  403.         if (strncmp(scb->buf,read_cmd,strlen(read_cmd)) == 0)
  404.             read_message(scb);
  405.  
  406. #ifdef POP_FOLDERS
  407.  
  408.         else if (strncmp(scb->buf,fold_cmd,strlen(fold_cmd)) == 0)
  409.             select_folder(scb);
  410. #endif
  411.  
  412.         else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  413.             retrieve_message(scb);
  414.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  415.             do_cleanup(scb);
  416.         else
  417.             state_error(scb,
  418. #ifdef POP_FOLDERS
  419.                "(ITEM) Expected FOLD, READ, RETR, or QUIT command");
  420. #else
  421.                "(ITEM) Expected READ, RETR, or QUIT command");
  422. #endif
  423.         break;
  424.  
  425.     case NEXT:
  426.         if (strncmp(scb->buf,ackd_cmd,strlen(ackd_cmd)) == 0){
  427.                 /* ACKD processing */
  428.             deletemsg(scb,scb->msg_num);
  429.             scb->msg_num++;
  430.             get_message(scb,scb->msg_num);
  431.         } else if (strncmp(scb->buf,acks_cmd,strlen(acks_cmd)) == 0){
  432.                 /* ACKS processing */
  433.             scb->msg_num++;
  434.             get_message(scb,scb->msg_num);
  435.         } else if (strncmp(scb->buf,nack_cmd,strlen(nack_cmd)) == 0){
  436.                 /* NACK processing */
  437.             fseek(scb->wf,scb->curpos,SEEK_SET);
  438.         } else {
  439.             state_error(scb,"(NEXT) Expected ACKD, ACKS, or NACK command");
  440.             return;
  441.         }
  442.  
  443.         print_message_length(scb);
  444.         scb->state  = ITEM;
  445.         break;
  446.  
  447.     case DONE:
  448.         do_cleanup(scb);
  449.         break;
  450.  
  451.     default:
  452.         state_error(scb,"(TOP) State Error!!");
  453.         break;
  454.     }
  455.  
  456. #ifdef DEBUG
  457.     if(Mailtrace >= 3)
  458.         tprintf("POP2SERV(pop_sm): Leaving state machine; state %u\n",scb->state);
  459. #endif /* DEBUG */
  460. }
  461.  
  462. static void
  463. #ifdef PROTOTYPES
  464. do_cleanup(struct pop_scb *scb)
  465. #else
  466. do_cleanup(scb)
  467. struct pop_scb *scb;
  468. #endif
  469. {
  470. #ifndef __TURBOC__
  471.     static
  472. #endif
  473.     void close_folder(struct pop_scb *);
  474.  
  475.     close_folder(scb);
  476.     (void) usprintf(scb->socket,signoff_msg);
  477.     scb->state = DONE;
  478. }
  479.  
  480. static void
  481. #ifdef PROTOTYPES
  482. state_error(struct pop_scb *scb,char *msg)
  483. #else
  484. state_error(scb,msg)
  485. struct pop_scb *scb;
  486. char *msg;
  487. #endif
  488. {
  489.     if(Mailtrace >= 2)
  490.         tprintf(error_rsp,msg);
  491.     (void) usprintf(scb->socket,error_rsp,msg);
  492.     scb->state = DONE;
  493. }
  494.  
  495. #ifdef POP_FOLDERS
  496.  
  497. static void
  498. select_folder(scb)
  499. struct pop_scb  *scb;
  500. {
  501.     sscanf(scb->buf,"FOLD %s",scb->username);
  502.  
  503.     if (scb->wf != NULL)
  504.         close_folder(scb);
  505.  
  506.     open_folder(scb);
  507. }
  508.  
  509. #endif
  510.  
  511.  
  512. static void
  513. #ifdef PROTOTYPES
  514. close_folder(struct pop_scb *scb)
  515. #else
  516. close_folder(scb)
  517. struct pop_scb *scb;
  518. #endif
  519. {
  520.     char folder_pathname[64];
  521.     char line[TLINELEN+1];
  522.     FILE *fd;
  523.     int deleted = FALSE;
  524.     int msg_no = 0;
  525. /*    struct stat folder_stat; */
  526. #ifndef __TURBOC__
  527.     static
  528. #endif
  529.     int newmail(struct pop_scb *);
  530. #ifndef __TURBOC__
  531.     static
  532. #endif
  533.     int isdeleted(struct pop_scb *,int);
  534.  
  535.     if (scb->wf == NULL)
  536.         return;
  537.  
  538.     if (!scb->folder_modified) {
  539.         /* no need to re-write the folder if we have not modified it */
  540.  
  541.         fclose(scb->wf);
  542.         scb->wf = NULL;
  543.  
  544.         free((char *)scb->msg_status);
  545.         scb->msg_status = NULL;
  546.         return;
  547.     }
  548.  
  549.  
  550.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  551.  
  552.     if (newmail(scb)) {
  553.         /* copy new mail into the work file and save the
  554.            message count for later */
  555.  
  556.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  557.             state_error(scb,"Unable to add new mail to folder");
  558.             return;
  559.         }
  560.  
  561.         fseek(scb->wf,0,SEEK_END);
  562.         fseek(fd,scb->folder_file_size,SEEK_SET);
  563.         while (!feof(fd)) {
  564.             fgets(line,TLINELEN,fd);
  565.             fputs(line,scb->wf);
  566.         }
  567.  
  568.         fclose(fd);
  569.     }
  570.  
  571.     /* now create the updated mail folder */
  572.  
  573.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  574.         state_error(scb,"Unable to update mail folder");
  575.         return;
  576.     }
  577.  
  578.     rewind(scb->wf);
  579.     while (!feof(scb->wf)){
  580.         fgets(line,TLINELEN,scb->wf);
  581.  
  582.         if (isSOM(line)){
  583.             msg_no++;
  584.             if (msg_no <= scb->folder_len)
  585.                 deleted = isdeleted(scb,msg_no);
  586.             else
  587.                 deleted = FALSE;
  588.         }
  589.  
  590.         if (deleted)
  591.             continue;
  592.  
  593.         fputs(line,fd);
  594.     }
  595.  
  596.     fclose(fd);
  597.  
  598.     /* trash the updated mail folder if it is empty */
  599.  
  600. /*      if ((stat(folder_pathname,&folder_stat) == 0) && (folder_stat.st_size == 0)) */
  601.     if(fsize(folder_pathname) == 0L)                /* N1BEE */
  602.         unlink(folder_pathname);
  603.  
  604.     fclose(scb->wf);
  605.     scb->wf = NULL;
  606.  
  607.     free((char *)scb->msg_status);
  608.     scb->msg_status = NULL;
  609. }
  610.  
  611. static void
  612. #ifdef PROTOTYPES
  613. open_folder(struct pop_scb *scb)
  614. #else
  615. open_folder(scb)
  616. struct pop_scb  *scb;
  617. #endif
  618. {
  619.     char folder_pathname[64];
  620.     char line[TLINELEN+1];
  621.     FILE *fd;
  622. /*      FILE *tmpfile();                should not declare here -- N1BEE */
  623.     struct stat folder_stat;
  624.  
  625.  
  626.     sprintf(folder_pathname,"%.45s/%.8s.txt",Mailspool,scb->username);
  627. #ifdef DEBUG
  628.     if(Mailtrace >= 3) {
  629.         tprintf("POP2SERV(open_folder): will open %s\n",folder_pathname);
  630.     }
  631. #endif /* DEBUG */
  632.     scb->folder_len       = 0;
  633.     scb->folder_file_size = 0;
  634.  
  635.     /* Ordinarily, we would call stat() to find out if the file exists
  636.        and get its size at the same time.  However, there is a bug in
  637.        Borland's stat() code which crashes DesqView and OS/2 (!) if
  638.        stat() is called on a file which does not exist.  -- N1BEE
  639.     */
  640.  
  641.     /* if (stat(folder_pathname,&folder_stat)){ */
  642.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  643. #ifdef DEBUG
  644.         if(Mailtrace >= 3) {
  645.             tprintf("POP2SERV(open_folder): folder not found (empty)\n");
  646.         }
  647. #endif /* DEBUG */
  648.         (void) usprintf(scb->socket,no_mail_rsp);
  649.  
  650.         /* state remains AUTH, expecting HELO or QUIT */
  651.         return;
  652.     }
  653.  
  654.     scb->folder_file_size = folder_stat.st_size;
  655.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  656.         state_error(scb,"POP2SERV(open_folder): Unable to open mail folder");
  657.         return;
  658.     }
  659.  
  660.     if ((scb->wf = tmpfile()) == NULL) {
  661.         state_error(scb,"POP2SERV(open_folder): Unable to create work folder");
  662.         return;
  663.     }
  664.  
  665.     while(!feof(fd)) {
  666.         fgets(line,TLINELEN,fd);
  667.  
  668.         /* scan for begining of a message */
  669.  
  670.         if (isSOM(line))
  671.             scb->folder_len++;
  672.  
  673.         /* now put  the line in the work file */
  674.  
  675.         fputs(line,scb->wf);
  676.     }
  677.  
  678.     fclose(fd);
  679.  
  680.     scb->msg_status_size = (scb->folder_len) / BITS_PER_WORD;
  681.  
  682.     if ((((scb->folder_len) % BITS_PER_WORD) != 0) ||
  683.         (scb->msg_status_size == 0))
  684.         scb->msg_status_size++;
  685.  
  686.     if ((scb->msg_status = (int16 *)callocw((unsigned)scb->msg_status_size,
  687.                 sizeof(int16))) == NULL) {
  688.         state_error(scb,"Unable to create message status array");
  689.         return;
  690.     }
  691.  
  692.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  693.  
  694.     scb->state  = MBOX;
  695.  
  696. #ifdef DEBUG
  697.     if(Mailtrace >= 3)
  698.         tprintf("POP2SERV: open_folder() completed successfully.\n");
  699. #endif /* DEBUG */
  700. }
  701.  
  702. static void
  703. #ifdef PROTOTYPES
  704. read_message(struct pop_scb *scb)
  705. #else
  706. read_message(scb)
  707. struct pop_scb  *scb;
  708. #endif
  709. {
  710. #ifndef __TURBOC__
  711.     static
  712. #endif
  713.     void get_message(struct pop_scb *,int);
  714. #ifndef __TURBOC__
  715.     static
  716. #endif
  717.     void print_message_length(struct pop_scb *);
  718.  
  719.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  720.         return;
  721.     if (scb->buf[sizeof(read_cmd) - 1] == ' ')
  722.         scb->msg_num = atoi(&(scb->buf[sizeof(read_cmd) - 1]));
  723.     else
  724.         scb->msg_num++;
  725.  
  726.     get_message(scb,scb->msg_num);
  727.     print_message_length(scb);
  728.     scb->state  = ITEM;
  729. }
  730.  
  731. static void
  732. #ifdef PROTOTYPES
  733. retrieve_message(struct pop_scb *scb)
  734. #else
  735. retrieve_message(scb)
  736. struct pop_scb  *scb;
  737. #endif
  738. {
  739.     char line[TLINELEN+1];
  740.     long cnt;
  741.  
  742.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  743.         return;
  744.     if (scb->msg_len == 0) {
  745.         state_error(scb,"Attempt to access a DELETED message!");
  746.         return;
  747.     }
  748.  
  749.     cnt  = scb->msg_len;
  750.     while(!feof(scb->wf) && (cnt > 0)) {
  751.         fgets(line,TLINELEN,scb->wf);
  752.         rrip(line);
  753.  
  754.         (void) usprintf(scb->socket,msg_line,line);
  755.         cnt -= (strlen(line)+2);        /* Compensate for CRLF */
  756.     }
  757.  
  758.     scb->state = NEXT;
  759. }
  760.  
  761. static void
  762. #ifdef PROTOTYPES
  763. get_message(struct pop_scb *scb,int msg_no)
  764. #else
  765. get_message(scb,msg_no)
  766. struct pop_scb  *scb;
  767. int msg_no;
  768. #endif
  769. {
  770.     char line[TLINELEN+1];
  771.     long ftell __ARGS((FILE *));
  772. #ifndef __TURBOC__
  773.     static
  774. #endif
  775.     int isdeleted __ARGS((struct pop_scb *, int));
  776.  
  777.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  778.         return;
  779.     scb->msg_len = 0;
  780.     if (msg_no > scb->folder_len) {
  781.         scb->curpos  = 0;
  782.         scb->nextpos = 0;
  783.         return;
  784.     } else {
  785.         /* find the message and its length */
  786.  
  787.         rewind(scb->wf);
  788.         while (!feof(scb->wf) && (msg_no > -1)) {
  789.             if (msg_no > 0)
  790.                 scb->curpos = ftell(scb->wf);
  791.             
  792.             fgets(line,TLINELEN,scb->wf);
  793.             rrip(line);
  794.  
  795.             if (isSOM(line))
  796.                 msg_no--;
  797.  
  798.             if (msg_no != 0)
  799.                 continue;
  800.  
  801.             scb->nextpos  = ftell(scb->wf);
  802.             scb->msg_len += (strlen(line)+2);       /* Add CRLF */
  803.         }
  804.     }
  805.  
  806.     if (scb->msg_len > 0)
  807.         fseek(scb->wf,scb->curpos,SEEK_SET);
  808.  
  809.     /* we need the pointers even if the message was deleted */
  810.  
  811.     if  (isdeleted(scb,scb->msg_num))
  812.         scb->msg_len = 0;
  813. }
  814.  
  815. static int
  816. poplogin(username,pass)
  817. char *pass;
  818. char *username;
  819. {
  820.     char buf[80];
  821.     char *cp;
  822.     char *cp1;
  823.     FILE *fp;
  824.  
  825. #ifdef DEBUG
  826.     if(Mailtrace >= 3)
  827.         tprintf("POP2SERV(poplogin): Opening POP users file %s\n",Popusers);
  828. #endif /* DEBUG */
  829.  
  830.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  831.         /* User file doesn't exist */
  832.         tprintf("POP2 users file %s not found\n",Popusers);
  833.         return(FALSE);
  834.     }
  835.  
  836. #ifdef DEBUG
  837.     if(Mailtrace >= 3)
  838.         tprintf("POP2SERV(poplogin): Login request from %s:%s:\n",username,pass);
  839. #endif /* DEBUG */
  840.  
  841.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  842.         if(buf[0] == '#')
  843.             continue;       /* Comment */
  844.  
  845.         if((cp = strchr(buf,':')) == NULLCHAR)
  846.             /* Bogus entry */
  847.             continue;
  848.  
  849.         *cp++ = '\0';           /* Now points to password */
  850.         if(strcmp(username,buf) == 0)
  851.             break;          /* Found user name */
  852.     }
  853.  
  854.     if(feof(fp)) {
  855. #ifdef DEBUG
  856.         if(Mailtrace >= 3)
  857.             tprintf("POP2SERV(poplogin): username not found in POPUSERS\n");
  858. #endif /* DEBUG */
  859.         /* User name not found in file */
  860.  
  861.         fclose(fp);
  862.         return(FALSE);
  863.     }
  864.     fclose(fp);
  865.  
  866.     if ((cp1 = strchr(cp,':')) == NULLCHAR) {
  867. #ifdef DEBUG
  868.         if(Mailtrace >= 3)
  869.             tprintf("POP2SERV(poplogin): No second ':' in POPUSERS entry\n");
  870. #endif /* DEBUG */
  871.         return(FALSE);
  872.     }
  873.  
  874.     *cp1 = '\0';
  875.     if(strcmp(cp,pass) != 0) {
  876. #ifdef DEBUG
  877.         if(Mailtrace >= 3)
  878.             tprintf("POP2SERV(poplogin): Wrong password (%s) from user %s, expecting %s\n",pass,username,cp);
  879. #endif /* DEBUG */
  880.         /* Password required, but wrong one given */
  881.         return(FALSE);
  882.     }
  883.  
  884.     /* whew! finally made it!! */
  885. #ifdef DEBUG
  886.     if(Mailtrace >= 3)
  887.         tprintf("POP2SERV(poplogin): %s authenticated\n",username);
  888. #endif /* DEBUG */
  889.  
  890.     return(TRUE);
  891. }
  892.  
  893. static int
  894. #ifdef PROTOTYPES
  895. isdeleted(struct pop_scb *scb,int msg_no)
  896. #else
  897. isdeleted(scb,msg_no)
  898. struct pop_scb *scb;
  899. int msg_no;
  900. #endif
  901. {
  902.     int16 mask = 1,offset;
  903.  
  904.     msg_no--;
  905.     offset = msg_no / BITS_PER_WORD;
  906.     mask <<= msg_no % BITS_PER_WORD;
  907.     return (((scb->msg_status[offset]) & mask)? TRUE:FALSE);
  908. }
  909.  
  910. static void
  911. #ifdef PROTOTYPES
  912. deletemsg(struct pop_scb *scb,int msg_no)
  913. #else
  914. deletemsg(scb,msg_no)
  915. struct pop_scb *scb;
  916. int msg_no;
  917. #endif
  918. {
  919.     int16 mask = 1,offset;
  920.  
  921.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  922.         return;
  923.     msg_no--;
  924.     offset = msg_no / BITS_PER_WORD;
  925.     mask <<= msg_no % BITS_PER_WORD;
  926.     scb->msg_status[offset] |= mask;
  927.     scb->folder_modified = TRUE;
  928. }
  929.  
  930. static int
  931. #ifdef PROTOTYPES
  932. newmail(struct pop_scb *scb)
  933. #else
  934. newmail(scb)
  935. struct pop_scb *scb;
  936. #endif
  937. {
  938.     char folder_pathname[64];
  939.     struct stat folder_stat;
  940.  
  941.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  942.  
  943.     /* if (stat(folder_pathname,&folder_stat)) { */
  944.     if((folder_stat.st_size = fsize(folder_pathname)) == -1L) { /* N1BEE */
  945.         state_error(scb,"Unable to get old mail folder's status");
  946.         return(FALSE);
  947.     } else
  948.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  949. }
  950.  
  951. static void
  952. #ifdef PROTOTYPES
  953. print_message_length(struct pop_scb *scb)
  954. #else
  955. print_message_length(scb)
  956. struct pop_scb *scb;
  957. #endif
  958. {
  959.     char *print_control_string;
  960.  
  961.     if (scb == NULLSCB)     /* check for null -- wa6smn */
  962.         return;
  963.     if (scb->msg_len > 0)
  964.         print_control_string = length_rsp;
  965.     else if (scb->msg_num <= scb->folder_len)
  966.         print_control_string = length_rsp;
  967.     else
  968.         print_control_string = no_more_rsp;
  969.  
  970.     (void)usprintf(scb->socket,print_control_string,scb->msg_len,scb->msg_num);
  971. }
  972.  
  973. #endif
  974.